package com.eva.core.config.security;

import com.eva.core.model.LoginUserInfo;
import com.eva.core.utils.Utils;
import com.eva.service.system.LoginTokenService;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 预认证过滤器，用于在进行认证之前填入用户信息（如果有）
 */
@Component
public class DefaultPreAuthFilter extends BasicAuthenticationFilter {

    @Resource
    private UserDetailsCache userDetailsCache;

    @Resource
    private LoginTokenService loginTokenService;

    public DefaultPreAuthFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = loginTokenService.get(request);
        // 没有token，直接放行
        if (token == null) {
            filterChain.doFilter(request, response);
            return;
        }
        // 从缓存中获取用户信息
        LoginUserInfo loginUserInfo = userDetailsCache.get(token);
        // 如果存在登录信息，则将用户信息写入Security上下文
        if (loginUserInfo != null) {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUserInfo, null, loginUserInfo.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
            // 如果为交互式会话，则延长会话的过期时间
            if ("INTERACTIVE".equals(Utils.AppConfig.getSession().getMode())) {
                userDetailsCache.relive(token);
            }
        }
        super.doFilterInternal(request, response, filterChain);
    }
}
